package com.plm.mqshequ.controller;

import com.alibaba.fastjson.JSON;
import com.google.code.kaptcha.Constants;
import com.plm.mqshequ.entity.*;
import com.plm.mqshequ.nosql.MongoPostOps;
import com.plm.mqshequ.nosql.MongoReplyOps;
import com.plm.mqshequ.nosql.RedisSetOps;
import com.plm.mqshequ.nosql.RedisStringOps;
import com.plm.mqshequ.service.RoleService;
import com.plm.mqshequ.service.UserService;
import com.plm.mqshequ.utils.ResultMsg;
import com.plm.mqshequ.utils.SessionUtils;
import com.plm.mqshequ.utils.StrUtils;
import io.lettuce.core.dynamic.annotation.Param;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import java.io.File;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author Limi
 * @create 2019-01-18 20:42
 */
@Slf4j
@RestController
@RequestMapping("/post")
public class PostController {

    @Value("${imgserver.dir}")
    private String saveDir;
    @Value("${imgserver.url}")
    private String imgUrl;

    @Autowired
    private UserService userService;
    @Autowired
    private MongoPostOps postOps;
    @Autowired
    private MongoReplyOps replyOps;
    @Autowired
    private RedisStringOps strOps;
    @Autowired
    private RedisSetOps setOps;
    @Autowired
    private RoleService roleService;

    @GetMapping("/index")
    public ModelAndView index(Model model){
        ModelAndView mv = new ModelAndView("jie/index");
        User user = SessionUtils.getUser();
        PageModel pageModel = new PageModel(1, 20);
        pageModel = postOps.findByPage(pageModel);
        model.addAttribute("user", user)
                .addAttribute("posts", pageModel.getList())
                .addAttribute("total", pageModel.getTotal())
                .addAttribute("column", "main")
                .addAttribute("filter", "0");
        return mv;
    }

    @GetMapping("/page/{column}/{filter}/{page}")
    public ModelAndView page(@PathVariable("page") String page, @PathVariable("filter") String filter,
                             @PathVariable("column") String column, Model model){
        ModelAndView mv = new ModelAndView("jie/index_page");
        User user = SessionUtils.getUser();
        PageModel pageModel = new PageModel(Integer.valueOf(page), 20);
        pageModel = postOps.findByPage(pageModel, column, filter);
        model.addAttribute("user", user)
                .addAttribute("posts", pageModel.getList())
                .addAttribute("curr", Integer.valueOf(page))
                .addAttribute("limit", pageModel.getLimit())
                .addAttribute("total", pageModel.getTotal())
                .addAttribute("pages", pageModel.getPages())
                .addAttribute("column", column)
                .addAttribute("filter", filter);
        return mv;
    }

    /**
     * @param filter 0综合，1未结，2已结，3精华
     * @param column 0提问，99分享，100讨论，101建议，168公告，169动态
     */
    @GetMapping("/query/{column}/{filter}")
    public ModelAndView query(@PathVariable("filter") String filter, @PathVariable("column") String column, Model model){
        ModelAndView mv = new ModelAndView("jie/index");
        User user = SessionUtils.getUser();
        PageModel pageModel = new PageModel(1, 20);//默查询第一页
        pageModel = postOps.findByPage(pageModel, column, filter);
        model.addAttribute("user", user)
                .addAttribute("posts", pageModel.getList())
                .addAttribute("curr", Integer.valueOf(1))
                .addAttribute("limit", pageModel.getLimit())
                .addAttribute("total", pageModel.getTotal())
                .addAttribute("pages", pageModel.getPages())
                .addAttribute("column", column)
                .addAttribute("filter", filter);
        return mv;
    }

    @GetMapping("/add")
    public ModelAndView add(){
        ModelAndView mv = new ModelAndView("jie/add");
        return mv;
    }


    @GetMapping("/detail")
    public ModelAndView detail(){
        ModelAndView mv = new ModelAndView("jie/detail");
        return mv;
    }

    @GetMapping("/detail/{id}")
    public ModelAndView detail(@PathVariable("id") String id, Model model) {
        ModelAndView mv = new ModelAndView("jie/detail");
        try {
            Post post = postOps.findById(id);
            User postuser = userService.findById(post.getUid());
            List<Reply> replys = replyOps.findByPostId(post.get_id());

            Role role = roleService.queryByUId(postuser.getId());
            postuser.setRole(role.getRole());
            postuser.setRoleName(role.getName());

            //更新查看数,在登录的情况下，自己查看自己的帖子不计数
            User user1 = SessionUtils.getUser();
            updateNumLook(post, user1);

            //登录用户
            User user = SessionUtils.getUser();

            model.addAttribute("post", post)
                    .addAttribute("user", user)
                    .addAttribute("postuser", postuser)
                    .addAttribute("looker", user1)
                    .addAttribute("replys", replys)
                    .addAttribute("column", "main")
                    .addAttribute("filter", "0");

        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return mv;
    }

    private void updateNumLook(Post post, User user1) {
        Integer numLook = post.getNumLook();
        if (null == user1) {
            post.setNumLook(numLook + 1);
            postOps.updateNumLook(post);
        } else {
            User user2 = (User) SecurityUtils.getSubject().getPrincipal();
            if (!user2.getId().equals(user1.getId())) {
                postOps.updateNumLook(post);
            }
        }
    }

    @GetMapping("/detail/{column}/{filter}/{id}")
    public ModelAndView detail(@PathVariable("filter") String filter,  @PathVariable("column") String column
            ,@PathVariable("id") String id, Model model) {
        ModelAndView mv = new ModelAndView("jie/detail");
        try {
            Post post = postOps.findById(id);
            User postuser = userService.findById(post.getUid());
            List<Reply> replys = replyOps.findByPostId(post.get_id());

            Role role = roleService.queryByUId(postuser.getId());
            postuser.setRole(role.getRole());
            postuser.setRoleName(role.getName());

            //登录用户
            User user = SessionUtils.getUser();

            //更新查看数,在登录的情况下，自己查看自己的帖子不计数
            User user1 = SessionUtils.getUser();
            updateNumLook(post, user1);

            model.addAttribute("post", post)
                    .addAttribute("postuser", postuser)
                    .addAttribute("user", user)
                    .addAttribute("looker", user1)
                    .addAttribute("replys", replys)
                    .addAttribute("column", column)
                    .addAttribute("filter", filter);

        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return mv;
    }

    @GetMapping("/edit/{id}")
    public ModelAndView edit(@PathVariable("id") String id, Model model) {
        ModelAndView mv = new ModelAndView("jie/edit");
        try {
            Post post = postOps.findById(id);
            model.addAttribute("post", post);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return mv;
    }

    @PostMapping("/uploadImg")
    public ResultMsg uploadImage(@RequestParam("file") MultipartFile file) {
        try {
            if (null != file) {
                //生成时间戳作为文件名称
                Long fileName = Instant.now().toEpochMilli();
                //获得文件类型（判断如果不是图片文件类型，则禁止上传）
                String contentType = file.getContentType();
                log.info("------------>文件类型: {}", contentType);
                //获得文件后缀名称
                String suffix = contentType.substring(contentType.indexOf("/") + 1);
                log.info("------------>上传文件后缀: {}", suffix);
                //根据日期来创建对应的文件夹
                //DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
                //String datetime = dtf.format(LocalDate.now());
                //文件存放的目录
                String dir = saveDir;
                //如果不存在，则创建新文件夹
                File f = new File(dir);
                if (!f.exists()) {
                    f.mkdirs();
                }

                //新生成的文件名称
                String saveFileName = fileName + "." + suffix;
                log.info("------------>保存的文件名称: {}", saveFileName);
                //文件保存的完整路径
                String savePath = dir + File.separator + saveFileName;
                log.info("------------>文件保存的完整路径: {}", savePath);

                //复制操作
                //将图片从源位置复制到目标位置
                file.transferTo(new File(savePath));

                return ResultMsg.ok("上传成功", imgUrl + saveFileName);
            } else {
                return ResultMsg.error("文件为空");
            }

        } catch (Exception e) {
            log.error(e.getMessage());
            return ResultMsg.error("系统出错，请联系管理员");
        }

    }

    @PostMapping("/publishPost")
    public ResultMsg publishPost(@RequestParam Map<String, Object> params) {
        String authcode = (String)params.get("authcode");
        if (verifyAuthcode(authcode)) {
            return ResultMsg.error("验证码输入有误");
        }
        try {
            String postId = getPostId();
            Post post = JSON.parseObject(JSON.toJSONString(params), Post.class);
            User user = SessionUtils.getUser();

            //判断财富是否足够
            Integer treasure = user.getTreasure();
            if (treasure < post.getTreasure()) {
                return ResultMsg.error("您的财富余额已不足,可以通过回答问题或发布分享获取更多的财富");
            }

            post.set_id(postId);
            post.setUid(user.getId());
            post.setUsername(user.getUsername());
            post.setAvatar(user.getAvatar());
            post.setReply(null);//默认回复为空
            post.setTag("");//默认标签为空
            post.setIsEnd("1");//默认未结帖
            post.setNumLook(0);//查看数为0
            post.setNumReply(0);//回复数为0
            //帖子状态：-1被删除,0正常,1未审核(分享专栏需要审核)
            if("99".equals(post.getTopic())){
                post.setStatus("1");
            } else {
                post.setStatus("0");
            }
            post.setCreateTime(new Date());
            log.info("----------->post is {}", post);
            //存储到mongodb中
            postOps.save(post);

        } catch (Exception e) {
            log.error(e.getMessage());
            return ResultMsg.error("发布失败");
        }

        return ResultMsg.ok("发布成功", "post/index");
    }

    @PostMapping("/updatePost")
    public ResultMsg updatePost(@RequestParam Map<String, Object> params) {
        String authcode = (String)params.get("authcode");
        if (verifyAuthcode(authcode)) {
            return ResultMsg.error("验证码输入有误");
        }
        try {
            Post post = JSON.parseObject(JSON.toJSONString(params), Post.class);
            //存储到mongodb中
            postOps.update(post);
            log.info("----------->update: post is {}", post);

        } catch (Exception e) {
            log.error(e.getMessage());
            return ResultMsg.error("更新失败");
        }

        return ResultMsg.ok("更新成功", "post/index");
    }

    /**
     * 提交回答
     * @param params 提交内容
     * @return
     */
    @PostMapping("/reply")
    public ResultMsg reply(@RequestParam Map<String, Object> params){
        Object principal = SecurityUtils.getSubject().getPrincipal();
        if (principal == null) {
            return ResultMsg.error("登录后才可以回复");
        }

        Reply reply = JSON.parseObject(JSON.toJSONString(params), Reply.class);
        String _id = StrUtils.uuid();
        User user = SessionUtils.getUser();
        reply.set_id(_id);
        reply.setUid(user.getId());
        reply.setUsername(user.getUsername());
        reply.setRolename(user.getRoleName());
        reply.setAvatar(user.getAvatar());
        reply.setAccept("1");//是否被采纳：0被采纳,1未采纳
        reply.setStatus("0");//回复状态：-1被删除,0正常
        reply.setZan(0L);//点赞为0
        reply.setReplyTime(new Date());
        Post post = null;
        try {
            replyOps.save(reply);
            post = postOps.findById(reply.getPostId());
            // 评论数加一
            post.setNumReply(post.getNumReply()+1);
            postOps.updateNumReply(post);

        } catch (Exception e) {
            log.error(e.getMessage());
            return ResultMsg.error("回复失败");
        }

        return ResultMsg.ok("回复成功", "post/detail/" + post.get_id() + "#comment" );
    }

    /**
     * 收藏
     * @param postId 帖子ID
     * @return
     */
    @GetMapping("/collect/{postId}")
    public ResultMsg collect(@PathVariable("postId") String postId){
        //TODO 待处理

        return ResultMsg.ok();
    }

    /**
     * 采纳为最佳答案
     * @param replyId 回复ID
     * @return
     */
    @PostMapping("/accept")
    public ResultMsg accept(@Param("replyId") String replyId){
        Post post = null;
        Reply reply = null;
        try {
            reply = replyOps.findById(replyId);
            post = postOps.findById(reply.getPostId());
            User acceptUser = userService.findById(reply.getUid());
            User postUser = userService.findById(post.getUid());

            /*将采纳的回复添加到帖子中，并删除回复表中这条数据*/
            Reply reply1 = reply;
            reply1.setStatus("-1");
            reply1.setAccept("0");//被采纳
            replyOps.update(reply1);
            //将采纳的回答添加到帖子中
            Post post1 = post;
            post1.setReply(reply1);
            post1.setIsEnd("0");//采纳后结帖
            postOps.updateAll(post1);

            Integer acceptUserTreasure = acceptUser.getTreasure();
            Integer postUserTreasure = postUser.getTreasure();
            try {
                //被采纳的回复者得到财富，采纳者失去财富
                acceptUser.setTreasure(acceptUserTreasure + post.getTreasure());
                postUser.setTreasure(postUserTreasure - post.getTreasure());
                userService.updateTreasure(acceptUser);
                userService.updateTreasure(postUser);
            } catch (Exception e) {
                log.error(e.getMessage());
                //手动控制回滚
                acceptUser.setTreasure(acceptUserTreasure);
                postUser.setTreasure(postUserTreasure);
                userService.updateTreasure(acceptUser);
                userService.updateTreasure(postUser);
            }

        } catch (Exception e) {
            log.error(e.getMessage());
            //手动控制回滚
            postOps.updateAll(post);
            Reply rp = replyOps.findById(replyId);
            if(null == rp){
                replyOps.save(reply);
            }
            return ResultMsg.error("系统出错，请联系管理员");
        }

        return ResultMsg.ok("采纳成功", "post/detail/" + post.get_id());
    }

    /**
     * 点赞回答
     * @param replyId 回答id
     * @return
     */
    @PostMapping("/zan")
    public ResultMsg zan(@Param("replyId") String replyId){
        Object principal = SecurityUtils.getSubject().getPrincipal();
        if (principal == null) {
            return ResultMsg.error("请登录");
        }

        try {
            User user = SessionUtils.getUser();
            Long addMembers = setOps.sadd(replyId, user.getId());
            if (addMembers == 0 && setOps.sismember(replyId, user.getId())) {
                setOps.srem(replyId, user.getId());
            }
            if (addMembers > 0) {
                Reply reply = replyOps.findAllById(replyId);
                Long zan = reply.getZan()==null ? 0 : reply.getZan();
                reply.setZan(zan + addMembers);
                replyOps.update(reply);
            }
        } catch (Exception e) {
            return ResultMsg.error("系统出错，请联系管理员");
        }
        return ResultMsg.ok();
    }

    private boolean verifyAuthcode(String authcode) {
        String text = (String) SessionUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (!text.equals(authcode)) {
            return true;
        }
        return false;
    }

    /**
     * 同步获取帖子ID
     * @return
     */
    private synchronized String getPostId(){
        // 从redis中获取帖子id
        String postId = strOps.get("post_id");
        // 取出成功后自增一
        strOps.incr("post_id");
        return postId;
    }

}
